// TODO: add effect parameters here.

// Camera parameters
float4x4 View;
float4x4 Projection;
float2 ViewportScale;

// The current time in seconds.
float CurrentTime;

float Duration;
float DurationRandomness;
float3 Gravity;
float EndVelocity;
float4 MinColor;
float4 MaxColor;

float2 RotateSpeed;
float2 StartSize;
float2 EndSize;

// Particle texture and sampler;
texture Texture;

sampler Sampler = sampler_state
{
	Texture = <Texture>;

	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = Point;
	AddressU = Clamp;
	AddressV = Clamp;
};


struct VertexShaderInput
{
	float2 Corner : POSITION0;

	float3 Position : POSITION1;

	float3 Velocity : NORMAL0;

	float4 Random : COLOR0;
	float Time : TEXCOORD0;
    // TODO: add input channels such as texture
    // coordinates and vertex colors here.
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
	float4 Color : COLOR0;
	float2 TextureCoordinate : COLOR1;
    // TODO: add vertex shader outputs such as colors and texture
    // coordinates here. These values will automatically be interpolated
    // over the triangle, and provided as input to your pixel shader.
};

float4 ComputeParticlePosition(float3 aPosition, float3 aVelocity,
							   float aAge, float aNormalizedAge)
{
	float lStartVelocity = length(aVelocity);
	float lEndVelocity = lStartVelocity * EndVelocity;

	float lVelocityIntegral = lStartVelocity * aNormalizedAge +
								(lEndVelocity - lStartVelocity) * aNormalizedAge *
																  aNormalizedAge / 2;

	aPosition += normalize(aVelocity) * lVelocityIntegral * Duration;

	aPosition += Gravity * aAge * aNormalizedAge;

	return mul(mul(float4(aPosition, 1), View), Projection);
}							   

float ComputeParticleSize(float aRandomValue, float aNormalizedAge)
{
	float lStartSize = lerp(StartSize.x, StartSize.y, aRandomValue);
	float lEndSize = lerp(EndSize.x, EndSize.y, aRandomValue);

	float lSize = lerp(lStartSize, lEndSize, aNormalizedAge);
	return lSize * Projection._m11;
}

float4 ComputeParticleColor(float4 aProjectedPosition,
							float aRandomValue, float aNormalizedAge)
{
	float4 lColor = lerp(MinColor, MaxColor, aRandomValue);

	lColor.a *= aNormalizedAge * (1-aNormalizedAge) * (1-aNormalizedAge) * 6.7;

	return lColor;
}							

float2x2 ComputeParticleRotation(float aRandomValue, float aAge)
{
	float lRotateSpeed = lerp(RotateSpeed.x, RotateSpeed.y, aRandomValue);

	float lRotation = lRotateSpeed * aAge;

	float c = cos(lRotation);
	float s = sin(lRotation);

	return float2x2(c, -s, s, c);
}



VertexShaderOutput ParticleVertexShader(VertexShaderInput input)
{
    VertexShaderOutput output;

	float lAge = CurrentTime - input.Time;

	lAge *= 1 + input.Random.x * DurationRandomness;

	float lNormalizedAge = saturate(lAge/Duration);

	output.Position = ComputeParticlePosition(input.Position, input.Velocity,
											  lAge, lNormalizedAge);
	float lSize = ComputeParticleSize(input.Random.y, lNormalizedAge);
	float2x2 lRotation = ComputeParticleRotation(input.Random.w, lAge);
	output.Position.xy += mul(input.Corner, lRotation) * lSize * ViewportScale;

	output.Color = ComputeParticleColor(output.Position, input.Random.z, lNormalizedAge);
	output.TextureCoordinate = (input.Corner + 1)/2;

    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    // TODO: add your pixel shader code here.

    return tex2D(Sampler, input.TextureCoordinate) * input.Color;
}

technique Technique1
{
    pass Pass1
    {
        // TODO: set renderstates here.

        VertexShader = compile vs_2_0 ParticleVertexShader();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}
